/* Copyright (C) 2010 Luca Piccinelli
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

/* 
 * File:   main.cpp
 * Author: lpiccinelli
 *
 * Created on 3 agosto 2010, 21.34
 */

#include <cstdlib>
#include <iostream>

#include <boost/any.hpp>

#include <cv.h>
#include <highgui.h>

#include "prj_definitions.h"
#include "pipeline/adv_pipeline_data_structures.h"
#include "pipeline/pipeline_data_structures.h"
#include "pipeline/pipeline_io.h"
#include "generators/cameraInputGenerator.h"
#include "generators/genericGenerator.h"
#include "generators/bridgeGenerator.h"
#include "imgops/filters/GaussBlurOp.h"
#include "imgops/filters/SobelFilterOp.h"
#include "formatters/cvMat_formatters.h"

using namespace std;
using namespace cv;
using namespace NAMESPACE;


class KeyPressed{
public:
    bool operator()() const{
        if(waitKey(30) >= 0) return false;
        return true;
    }
};

class Test{
public:
    int* i;

    bool operator()() const{
        
        if((*i)++ > 30) return false;
        return true;
    }
};

int main(int argc, char** argv) {

    // Statistics
    clock_t start_time, end_time;
    float framerate = 0, seconds = 0;

    // Operations
    GaussBlurOp op_gauss;
    SobelFilterOp op_sobel;

    // gauss blur input
    CameraInputGenerator* cameraGenerator = new CameraInputGenerator(op_gauss.getInputKeysList().at(0));
    // gauss blur output
    GenericGenerator<Mat>* blur_out_generator = new GenericGenerator<Mat>(op_gauss.getOutputKeysList().at(0));
    // gauss blur criteria
    NumericIOElement width(5, op_gauss.getCriteriaKeysList().at(0));
    NumericIOElement height(5,op_gauss.getCriteriaKeysList().at(1));
    NumericIOElement sigmaX(2.0, op_gauss.getCriteriaKeysList().at(2));
    // -------------------------------------------------------------------------

    // ****** Sobel computation ************************************************
    // sobel input
    BridgeGenerator* sobel_generator = new BridgeGenerator(*blur_out_generator,
                                                            op_sobel.getInputKeysList().at(0));
    // sobel output
    GenericGenerator<Mat>* out_generator = new GenericGenerator<Mat>(op_sobel.getOutputKeysList().at(0));
    // sobel criteria
    NumericIOElement sobel_ddepth(CV_8U, op_sobel.getCriteriaKeysList().at(0));
    NumericIOElement sobel_xorder(1,op_sobel.getCriteriaKeysList().at(1));
    NumericIOElement sobel_yorder(1, op_sobel.getCriteriaKeysList().at(2));
    NumericIOElement sobel_scale(10.0, op_sobel.getCriteriaKeysList().at(4));
    // -------------------------------------------------------------------------
    

    blur_out_generator->set_max_buffer_mem(10000000);
    out_generator->set_max_buffer_mem(10000000);

    // ****** Output formatters ************************************************
    CvMatHgWndFormatter sobel_formatter(op_sobel.getOutputKeysList().at(0), "sobel");
    CvMatHgWndFormatter gauss_formatter(op_gauss.getOutputKeysList().at(0), "gauss");
    // -------------------------------------------------------------------------

    // ****** Gauss blur Pipestep **********************************************
    PipeStep blur_step;
    blur_step.set_computation(&op_gauss);
    blur_step.add_input_generator(cameraGenerator);     // Input
    blur_step.add_criteria(&width)                      // Criteria
             .add_criteria(&height)
             .add_criteria(&sigmaX);
    blur_step.add_output_generator(blur_out_generator); // Output
    
    blur_step.add_output_formatter(&gauss_formatter);
    // -------------------------------------------------------------------------

    // ****** Sobel Pipestep ***************************************************
    PipeStep sobel_step;
    sobel_step.set_computation(&op_sobel);
    sobel_step.add_input_generator(sobel_generator);    // Input
    sobel_step.add_criteria(&sobel_ddepth)              // Criteria
              .add_criteria(&sobel_xorder)
              .add_criteria(&sobel_yorder)
              .add_criteria(&sobel_scale);
    sobel_step.add_output_generator(out_generator);     // Output

    sobel_step.add_output_formatter(&sobel_formatter);
    // -------------------------------------------------------------------------

    
    // Pipeline
    Pipeline main_pipe;    
    main_pipe.add_pipe_step(&blur_step);
    main_pipe.add_pipe_step(&sobel_step);

    // Step of pipeline looping
    LoopPipeStep<KeyPressed> main_step;
    KeyPressed key_pressed;
    main_step.set_condition(key_pressed);
    
    main_step.set_computation(&main_pipe);

    cameraGenerator->open();
    start_time = clock();
    main_step.execute();
    end_time = clock();

    // ****** computing statistics *********************************************
    seconds = static_cast<float>(end_time - start_time) / static_cast<float>(CLOCKS_PER_SEC);
    framerate = static_cast<float>(main_step.get_loops()) / seconds;
    // -------------------------------------------------------------------------

    cout << framerate << " f/second" << endl;

    // ****** free resources ***************************************************
    delete cameraGenerator;
    delete sobel_generator;
    delete out_generator;
    delete blur_out_generator;
    // -------------------------------------------------------------------------

    return 0;
}